package com.gitee.center.runtime;

import com.gitee.center.runtime.def.*;
import com.sun.istack.internal.NotNull;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class InternalIndexer {
    static final Map<Class<? extends BaseDomainAbility>, DomainAbilityDef> domainAbilityDefMap = new HashMap<>();
    static final Map<String, DomainDef> domainDefMap = new HashMap<>();
    static final Map<Class<? extends IDomainExtension>, PolicyDef> policyDefMap = new HashMap<>();
    static final Map<Class<? extends IDomainExtension>, List<PatternDef>> sortedPatternMap = new HashMap<>();
    // 扩展点 Partner
    static final Map<String, PartnerDef> partnerDefMap = new ConcurrentHashMap<>();

    static final Map<String, PatternDef> patternDefMap = new HashMap<>();

    private static final List<StepDef> emptySteps = Collections.emptyList();

    static final Map<String, Map<String, StepDef>> domainStepDefMap = new HashMap<>(); // {activityCode, {stepCode, def}}

    private InternalIndexer() {
    }

    /**
     * 查找领域能力
     * @param clazz
     * @return
     * @param <T>
     */
    public static <T extends BaseDomainAbility> T findDomainAbility(@NotNull Class<? extends T> clazz) {
        DomainAbilityDef domainAbilityDef = domainAbilityDefMap.get(clazz);
        if (domainAbilityDef == null) {
            return null;
        }

        return (T) domainAbilityDef.getDomainAbilityBean();
    }

    @NotNull
    public static List<StepDef> findDomainSteps(@NotNull String activityCode, @NotNull List<String> stepCodeList) {
        Map<String, StepDef> childMap = domainStepDefMap.get(activityCode);
        if (childMap == null || childMap.isEmpty()) {
            return emptySteps;
        }

        List<StepDef> result = new LinkedList<>();
        for (String code : stepCodeList) {
            StepDef stepDef = childMap.get(code);
            if (stepDef != null) {
                result.add(stepDef);
            }
        }
        return result;
    }


    /**
     * 给定一个领域能力，找到它定义的扩展点接口
     * @param clazz
     * @return
     */
    public static Class<? extends IDomainExtension> getDomainAbilityExtDeclaration(@NotNull Class<? extends BaseDomainAbility> clazz) {
        DomainAbilityDef domainAbilityDef = domainAbilityDefMap.get(clazz);
        if (domainAbilityDef == null) {
            return null;
        }

        return domainAbilityDef.getExtClazz();
    }

    public static void index(DomainAbilityDef domainAbilityDef) {
        domainAbilityDefMap.put(domainAbilityDef.getDomainAbilityClass(), domainAbilityDef);
    }

    public static void index(DomainDef domainDef) {
        domainDefMap.put(domainDef.getCode(), domainDef);
    }

    public static void index(PolicyDef policyDef) {
        policyDefMap.put(policyDef.getExtClazz(), policyDef);
    }

    public static void index(PartnerDef partnerDef) {
        partnerDefMap.put(partnerDef.getCode(), partnerDef);
    }

    public static void index(StepDef stepDef) {
        if (!domainStepDefMap.containsKey(stepDef.getActivity())) {
            domainStepDefMap.put(stepDef.getActivity(), new HashMap<>());
        }

        Map<String, StepDef> childMap = domainStepDefMap.get(stepDef.getActivity());

        childMap.put(stepDef.getCode(), stepDef);

    }

    public static void index(ExtensionDef extensionDef) {
        if (policyDefMap.containsKey(extensionDef.getExtClazz())) {
            PolicyDef policyDef = policyDefMap.get(extensionDef.getExtClazz());
            policyDef.registerExtensionDef(extensionDef);
        }

        if (patternDefMap.containsKey(extensionDef.getCode())) {
            // 基于Pattern的扩展点，因为在pattern里找到了对应的code：extension.code = pattern.code
            PatternDef patternDef = patternDefMap.get(extensionDef.getCode());
            patternDef.registerExtensionDef(extensionDef);
        }

        if (partnerDefMap.containsKey(extensionDef.getCode())) {
            // 基于垂直业务的扩展点
            PartnerDef partnerDef = partnerDefMap.get(extensionDef.getCode());
            partnerDef.registerExtensionDef(extensionDef);
        }
    }

    @NotNull
    public static List<ExtensionDef> findEffectiveExtensions(@NotNull Class<? extends IDomainExtension> extClazz, @NotNull IDomainModel model, boolean firstStop) {
        List<ExtensionDef> effectiveExtensions = new LinkedList<>();
        PolicyDef policyDef = policyDefMap.get(extClazz);
        if (policyDef != null) {
            ExtensionDef extensionByPolicy = policyDef.getExtension(model);
            if (extensionByPolicy == null) {
                return effectiveExtensions;
            }

            effectiveExtensions.add(extensionByPolicy);
            return effectiveExtensions;
        }

        // Pattern优先：细粒度的扩展点
        // 否则，Pattern下的扩展点可能会被粗粒度的Partner下扩展点给盖住，无法执行
        // Partner=KA，在Partner下它实现了一个扩展点，这时候签约了一个新KA客户(宝胜)的逻辑稍有不同，因此实现了一个Pattern下的扩展点
        // 如果Partner优先，那么宝胜的扩展点实现永远不会被执行：它被Partner下的扩展点盖住了 -:(
        // 同时，Pattern是有优先级的，典型场景：一个Seller有一个Pattern，该Seller下有2个特殊的Dept，各自有自己的Pattern
        List<PatternDef> sortedPatternDefs = sortedPatternMap.get(extClazz);
        if (sortedPatternDefs != null && !sortedPatternDefs.isEmpty()) {
            // 该扩展点在一些Pattern上有实现，那么通过Pattern把扩展点实例找到
            for (PatternDef patternDef : sortedPatternDefs) {
                if (!patternDef.match(model)) {
                    continue;
                }

                // 找该Pattern下实现了该扩展点接口的实例
                ExtensionDef extensionDef = patternDef.getExtension(extClazz);
                if (extensionDef != null) {
                    effectiveExtensions.add(extensionDef);
                }

                if (firstStop && !effectiveExtensions.isEmpty()) {
                    return effectiveExtensions;
                }
            }
        }

        // 之后再找Partner
        for (PartnerDef partnerDef : partnerDefMap.values()) {
            //  过滤泛型
            //获取子类字节码文件对象，this代表的是子类对象。
            Class clazz = partnerDef.getPartnerBean().getClass();
            //获取子类所属接口的参数化类型,cn.xxx.xxx.BasicAction<cn.xxx.xxx.Standard>
            Type type = clazz.getGenericInterfaces()[0];
            //因为type是顶级接口没有定义任何方法，所以需要强转为子接口ParameterizedType
            ParameterizedType parameterizedType = (ParameterizedType) type;
            //通过子接口定义的getActualTypeArguments方法获取到实际参数类型,<cn.xxx.xxx.Standard>
            //返回参数为数组，因为Java中接口可以多实现
            Type[] types = parameterizedType.getActualTypeArguments();
            //获取数组中的实际参数类型
            Class generic = (Class) types[0];

            // TODO

            boolean assignableFrom = generic.isAssignableFrom(model.getClass());
            if (!assignableFrom) {
                continue;
            }
            if (!partnerDef.match(model)) {
                continue;
            }
            ExtensionDef extensionDef = partnerDef.getExtension(extClazz);
            if (extensionDef != null) {
                effectiveExtensions.add(extensionDef);
                break; // 垂直业务是互斥的，不可叠加的
            }
        }
        return effectiveExtensions;
    }
}
